package uk.org.landeg.euler.problems.unported;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;

public class Euler185 extends AbstractProblem{
	String cluesStr [] = {
	"5616185650518293 ;2 correct",
	"3847439647293047 ;1 correct",
	"5855462940810587 ;3 correct",
	"9742855507068353 ;3 correct",
	"4296849643607543 ;3 correct",
	"3174248439465858 ;1 correct",
	"4513559094146117 ;2 correct",
	"7890971548908067 ;3 correct",
	"8157356344118483 ;1 correct",
	"2615250744386899 ;2 correct",
	"8690095851526254 ;3 correct",
	"6375711915077050 ;1 correct",
	"6913859173121360 ;1 correct",
	"6442889055042768 ;2 correct",
	"2321386104303845 ;0 correct",
	"2326509471271448 ;2 correct",
	"5251583379644322 ;2 correct",
	"1748270476758276 ;3 correct",
	"4895722652190306 ;1 correct",
	"3041631117224635 ;3 correct",
	"1841236454324589 ;3 correct",
	"2659862637316867 ;2 correct"};
	
	class Solution {
		HashMap<Integer, ArrayList<Integer>> numbers = new HashMap<Integer, ArrayList<Integer> > ();
		public Solution() {
			ArrayList<Integer> sol = null;
			for (int loc = 0 ; loc < 16 ; loc++) {
				for (int s = 0 ; s <= 9 ; s++) {
					sol.add(s);
				}
				numbers.put(loc, sol);
			}
		}
	}
	
	class Clue {
		Integer numbers[];
		int correct;
		int remaining;
		
		public Clue () {
		}
		
		@Override
		public String toString() {
			String numStr = new String ("[");
			boolean first = true;
			for (int idx =0 ; idx < numbers.length ; idx++) {
				if (!first) {
					numStr += ", ";
				}
				numStr += (numbers[idx] == null) ? " " : numbers[idx]; 
				first = false;
			}
			numStr += "]";
			
			return "Clue [correct=" + correct + ", remaining=" + remaining + " numbers="
					+ numStr;
		}
		
		public boolean remove (int loc, int val) {
			if (numbers[loc] != null && numbers[loc].equals(val)) {
				numbers[loc] = null;
				remaining--;
				return true;
			}
			return false;
		}

		public boolean removeOthers (int loc, int val) {
			if (numbers[loc] != null && !numbers[loc].equals(val)) {
				numbers[loc] = null;
				remaining--;
				return true;
			}
			return false;
		}
		
		public void eliminate (int loc, int val) {
			if (remove (loc,val)) {
				correct--;
			}
		}
		
		public int getConfidence () {
			return (int)(((double)correct / (double)remaining * 1000.0));
		}
	}
	
	public Euler185() {
		// TODO Auto-generated constructor stub
	}
	
	ArrayList<Clue> clues ;
	
	@Override
	public String solve() {
		clues = parseClues();
		Collections.sort(clues, new correctHighSort());
		// remove numbers from clues that appear in the clue with zero correct;
		
		Clue nonCorrect = null;
		while ((nonCorrect = getNonCorrect()) != null) {
			removeAsIncorrect(nonCorrect);
			clues.remove(nonCorrect);
			Collections.sort(clues, new bestClueSort());
			setCorrect(8, 4);
			setCorrect(15,3);
			setCorrect(0, 8);
		}
		for (Clue c : clues) {
			System.out.println(c);
		}
		return null;
	}

	private void setCorrect (int loc, int value) {
		for (Clue c : clues) {
			c.removeOthers(loc, value);
		}
	}
	
	private void removeAsIncorrect (Clue incorrect) {
		for (Clue c : clues) {
			for (int id = 0 ; id < incorrect.numbers.length ; id++) {
				if (incorrect.numbers[id] != null) {
					c.remove(id, incorrect.numbers[id]);
				}
			}
		}
	}
	/**
	 * 
	 * @return clue with zero correct numbers
	 */
	private Clue getNonCorrect () {
		for (Clue c : clues) {
			if (c.correct == 0) {
				return c;
			}
		}
		return null;
	}
	
	ArrayList<Clue> parseClues () {
		ArrayList<Clue> clues = new ArrayList<Clue>();
		String toks [];
		for (String c : cluesStr) {
			Clue cl = new Clue();
			toks = c.split(" ");
			cl.numbers = new Integer[toks[0].trim().length()];
			int id = 0;
			for (char ch : toks[0].toCharArray()) {
				cl.numbers[id++] = Utils.charToInt(ch);
			}
			cl.correct = Integer.parseInt(toks[1].replace(";", "").trim());
			cl.remaining = cl.numbers.length;
			clues.add(cl);
		}
		return clues;
	}
	
	
	class correctHighSort implements Comparator<Clue> {
		public int compare(Clue arg0,Clue arg1) {
			return arg1.correct - arg0.correct; 
		}
	}	

	class bestClueSort implements Comparator<Clue> {
		public int compare(Clue arg0,Clue arg1) {
			return arg1.getConfidence() - arg0.getConfidence();  
		}
	}	
}


